﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Linq;

namespace Seven.Tools.Helper
{
    /// <summary>
    /// 序列化 JSON 工具
    /// </summary>
    public static class JsonHelper
    {
        /// <summary>
        /// 任意对象序列化
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="retain">保留属性</param>
        /// <param name="ignore">忽略属性</param>
        /// <param name="turns">要转换的属性</param>
        /// <returns>返回数据</returns>
        public static string Serialize(object obj,
            string[] retain = null,
            string[] ignore = null,
            IDictionary<string, string> turns = null)
        {
            var settings = new JsonSerializerSettings();

            if (retain != null || ignore != null || turns != null)
            {
                settings.ContractResolver = new CustomContractResolver(retain, ignore, turns);
            }

            IsoDateTimeConverter timeConverter = new IsoDateTimeConverter();
            timeConverter.DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss";
            settings.Converters.Add(timeConverter);

            return JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
        }

        /// <summary>
        /// 将对象序列化成json格式的字符串
        /// </summary>
        /// <param name="value">要序列化的对象</param>
        /// <returns></returns>
        public static string SerializeObject(object value)
        {
            return JsonConvert.SerializeObject(value);
        }

        /// <summary>
        /// 将对象序列化成json格式的字符串
        /// </summary>
        /// <param name="value">要序列化的对象</param>
        /// <param name="enumTransfer">枚举是否转换，默认转换</param>
        /// <returns></returns>
        public static string SerializeObject(object value, bool enumTransfer)
        {
            if (enumTransfer)
            {
                JsonSerializerSettings setting = new JsonSerializerSettings();
                //枚举值转换成字符串名字
                setting.Converters.Add(new StringEnumConverter());

                return SerializeObject(value, setting);
            }
            else
            { return SerializeObject(value); }
        }

        /// <summary>
        /// 将对象序列化成json格式的字符串
        /// </summary>
        /// <param name="value">要序列化的对象</param>
        /// <param name="type">日期格式化类型，默认格式不处理</param>
        /// <returns></returns>
        public static string SerializeObject(object value, DateFormatType type = DateFormatType.None)
        {
            if (type == DateFormatType.None)
            {
                return SerializeObject(value);
            }
            else
            {
                JsonSerializerSettings setting = new JsonSerializerSettings();
                //这里使用自定义日期格式，默认是ISO8601格式
                IsoDateTimeConverter timeConverter = new IsoDateTimeConverter();
                switch (type)
                {
                    case DateFormatType.标准年月日: timeConverter.DateTimeFormat = "yyyy-MM-dd"; break;
                    case DateFormatType.年月日时: timeConverter.DateTimeFormat = "yyyy-MM-dd HH"; break;
                    case DateFormatType.年月日时分: timeConverter.DateTimeFormat = "yyyy-MM-dd HH:mm"; break;
                    case DateFormatType.年月日时分秒: timeConverter.DateTimeFormat = "yyyy-MM-dd HH:mm:ss"; break;
                    default: timeConverter.DateTimeFormat = "yyyy-MM-dd"; break;
                }
                setting.Converters.Add(timeConverter);
                return SerializeObject(value, setting);
            }
        }

        /// <summary>
        /// 将对象序列化成json格式的字符串
        /// </summary>
        /// <param name="value">要序列化的对象</param>
        /// <param name="enumTransfer">枚举是否转换</param>
        /// <param name="type">日期格式化类型</param>
        /// <returns></returns>
        public static string SerializeObject(object value, bool enumTransfer, DateFormatType type)
        {
            JsonSerializerSettings JsonSetting = new JsonSerializerSettings();
            if (enumTransfer)
            {
                //枚举值转换成字符串名字
                JsonSetting.Converters.Add(new StringEnumConverter());
            }

            if (type == DateFormatType.None)
            {
                return SerializeObject(value, JsonSetting);
            }
            else
            {
                //这里使用自定义日期格式，默认是ISO8601格式
                IsoDateTimeConverter timeConverter = new IsoDateTimeConverter();
                switch (type)
                {
                    case DateFormatType.标准年月日: timeConverter.DateTimeFormat = "yyyy-MM-dd"; break;
                    case DateFormatType.年月日时: timeConverter.DateTimeFormat = "yyyy-MM-dd HH"; break;
                    case DateFormatType.年月日时分: timeConverter.DateTimeFormat = "yyyy-MM-dd HH:mm"; break;
                    case DateFormatType.年月日时分秒: timeConverter.DateTimeFormat = "yyyy-MM-dd HH:mm:ss"; break;
                    default: timeConverter.DateTimeFormat = "yyyy-MM-dd"; break;
                }
                JsonSetting.Converters.Add(timeConverter);
                return SerializeObject(value, JsonSetting);
            }
        }

        /// <summary>
        /// 将对象序列化成json格式的字符串
        /// </summary>
        /// <param name="value">要序列化的对象</param>
        /// <param name="setting">序列化设置</param>
        /// <returns></returns>
        public static string SerializeObject(object value, JsonSerializerSettings setting)
        {
            return JsonConvert.SerializeObject(value, setting);
        }

        /// <summary>
        /// 将对象序列化成json格式的字符串，并且转换对象中的枚举值为Text值
        /// </summary>
        /// <param name="value">要序列化的对象</param>
        /// <returns></returns>
        public static string SerializeObjectTransferEnum(object value)
        {
            return SerializeObject(value, true);
        }

        /// <summary>
        /// 将json格式的字符串反序列化成对象
        /// </summary>
        /// <param name="json">要反序列化的json字符串</param>
        /// <param name="type">指定类型</param>
        /// <returns></returns>
        public static object DeserializeObject(string json, Type type)
        {
            return JsonConvert.DeserializeObject(json, type);
        }

        /// <summary>
        /// 将json格式的字符串反序列化成指定类型的对象
        /// </summary>
        /// <typeparam name="T">指定类型</typeparam>
        /// <param name="json">要反序列化的json字符串</param>
        /// <returns></returns>
        public static T DeserializeObject<T>(string json)
        {
            return JsonConvert.DeserializeObject<T>(json);
        }

        public static object DeserializeJsToObject(string json, Type type)
        {
            JObject jsonBody = JObject.Parse(json);
            return new JsonSerializer().Deserialize(jsonBody.CreateReader(), type);
        }

        public static object DeserializeJsToObject<T>(string json)
        {
            return DeserializeJsToObject(json, typeof(T));
        }

        public static object DeserializeJsToArray<T>(string json)
        {
            JArray jsonRsp = JArray.Parse(json);
            IList<T> list = new List<T>();

            if (jsonRsp != null)
            {
                JsonSerializer js = new JsonSerializer();
                for (int i = 0; i < jsonRsp.Count; i++)
                {
                    object obj = js.Deserialize(jsonRsp[i].CreateReader(), typeof(T));
                    list.Add((T)obj);
                }
            }
            return list.AsEnumerable();
        }
    }

    public class CustomContractResolver : DefaultContractResolver
    {
        string[] retain = null;
        string[] ignore = null;
        IDictionary<string, string> turns = null;

        public CustomContractResolver(string[] retain = null, string[] ignore = null, IDictionary<string, string> turns = null)
        {
            //指定要序列化属性的清单
            this.retain = retain;
            //指定要忽略属性的清单
            this.ignore = ignore;
            //指定要转换名称属性的清单
            this.turns = turns;
        }

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            List<JsonProperty> list = base.CreateProperties(type, memberSerialization).ToList();

            if (retain != null)
            {
                //只保留清单有列出的属性
                list = list.Where(p => retain.Contains(p.PropertyName)).ToList();
            }

            if (ignore != null)
            {
                //只保留清单有列出的属性
                list = list.Where(p => !ignore.Contains(p.PropertyName)).ToList();
            }

            if (turns != null)
            {
                //修改需要修改名称的属性
                foreach (var turn in turns)
                {
                    list.ForEach(new Action<JsonProperty>((m) =>
                    {
                        if (m.PropertyName == turn.Key)
                        {
                            m.PropertyName = turn.Value;
                        }
                    }));
                }
            }

            return list;
        }
    }

    /// <summary>
    /// 日期格式化类型
    /// </summary>
    public enum DateFormatType
    {
        None = 1,

        标准年月日 = 2,

        年月日时 = 4,

        年月日时分 = 8,

        年月日时分秒 = 16
    }
}
